package com.ideaaedi.component.compile;

import org.apache.commons.io.IOUtils;

import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URI;
import java.nio.charset.StandardCharsets;

/**
 * {@link SimpleJavaFileObject}是jdk提供的一个处理类源码的简单实现，源文件是以文件路径的形式输入的。
 * 如果你想源文件以{@link InputStream}或<code>byte[]</code>或{@link String}等形式输入，
 * 那么你需要对{@link SimpleJavaFileObject}进行扩展，或者直接实现{@link JavaFileObject}也行
 *
 * <p>
 * 注：事实上，{@link SimpleJavaFileObject}不仅仅能处理.java源文件，还能处理.class、.html等其它文件
 * @author JustryDeng
 * @since 2021/9/20 15:56:07
 */
public class CharSequenceJavaFileObject extends SimpleJavaFileObject {
    
    public static final String PKG_SEPARATOR = ".";
    
    public static final String DIR_SEPARATOR = "/";
    
    /**
     * 全类名
     */
    private final String classLongName;
    
    /**
     * 源码
     */
    private final CharSequence sourceCode;
    
    /**
     * 源码编译成功后的class
     */
    private ByteArrayOutputStream byteArrayOutputStream;
    
    public CharSequenceJavaFileObject(String classLongName, InputStream sourceCodeInputStream) {
        super(URI.create("CharSequence://" + classLongName.replace(PKG_SEPARATOR, DIR_SEPARATOR)
                + Kind.SOURCE.extension), Kind.SOURCE);
        this.classLongName = classLongName;
        try {
            this.sourceCode = sourceCodeInputStream == null ? null : IOUtils.toString(sourceCodeInputStream, StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    
    public CharSequenceJavaFileObject(String classLongName, CharSequence sourceCode) {
        super(URI.create("CharSequence://" + classLongName.replace(PKG_SEPARATOR, DIR_SEPARATOR)
                + Kind.SOURCE.extension), Kind.SOURCE);
        this.classLongName = classLongName;
        this.sourceCode = sourceCode;
    }
    
    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
        return sourceCode;
    }
    
    @Override
    public String getName() {
        return classLongName;
    }
    
    /**
     * 编译成功后，会将编译出来的.class往此方法开发的OutputStream中写
     */
    @Override
    public OutputStream openOutputStream() {
        if (byteArrayOutputStream == null) {
            byteArrayOutputStream = new ByteArrayOutputStream();
        }
        return byteArrayOutputStream;
    }
    
    public byte[] getByteCode() {
        return byteArrayOutputStream.toByteArray();
    }
}
